const sha1 = require('sha1');
const path = require('path');
const fs = require('fs');
const sendfile = require('koa-sendfile');
const archiver = require('archiver');
const redisCli = require('../../dbs/redisCli').client;
const createToken = require('../../utils/createToken');
const captcha = require('../../utils/captcha');
const cf = require('../../common_fn/commonFn');
const setCookie = require('../../utils/setCookie');
const checkParams = require('../../utils/checkParams');
const fileModel = require('../../models/file');
const getUsername = require('../../utils/getUsername');
const uploadController = require('.././../utils/FileOp').upload;
const makeDir = require('.././../utils/FileOp').makeDir;
const existsDir = require('.././../utils/FileOp').existsDir;
const deleteFile = require('.././../utils/FileOp').deleteFile;
const getHost = require('../../common_fn/CommonFn').getHost;
const checkLogin = require('../../utils/checkLogin');



class Controller {
    async upload(ctx,next){
        if (! await checkLogin(ctx)) {
            ctx.throw(401, 'invalid token');
        }
        let username = await getUsername(ctx);
        if (!await existsDir(path.join(__dirname, `../../public/files`))) {
            await makeDir(path.join(__dirname, `../../public/files`));
        }
        if (!await existsDir(path.join(__dirname, `../../public/files/${username}`))){
            await makeDir(path.join(__dirname, `../../public/files/${username}`));
        }
        if (ctx.request.method.toLowerCase() === 'post') {
            const ch = checkParams(['part','dir'],ctx.request.body.fields);
            if (!ch.status) {
                ctx.body = cf.dealMissArgsReq(ch.msg);
                return;
            }
            let params = ctx.request.body.fields;
            let { part,dir } = params;
            const files = ctx.request.body.files || {};
            //定义目录
            let nameSpace = Object.keys(files)[0];
            if (!nameSpace) {
                ctx.body = cf.dealErrorReq('未定义文件保存路径');
                return;
            }
            let originDir = path.join(__dirname, `../../public/files/${username}/${nameSpace}`);
            
            if (!await existsDir(originDir)){
                await makeDir(originDir);
                let idx = 0;
                let reg = /\\/ig;
                await fileModel.find({
                    username:username,
                    dir:originDir.replace(reg,'/').split('public')[1].split(nameSpace)[0],
                    isFile:0,
                    part:''
                }).count().then(num=>{
                    idx = num + 1;
                }).catch(error=>{
                    console.log(error);
                })
                let m = new fileModel({
                    username:username,
                    filename:nameSpace,
                    filepath:`/${nameSpace}`,
                    type:'dir',
                    size:0,
                    dir:originDir.replace(reg,'/').split('public')[1].split(nameSpace)[0],
                    isFile:0,
                    idx:idx,
                    key:`${new Date().getTime()+Math.random()}`
                });
                await m.save();
            }
            if (dir && dir.startsWith('/')){
                dir = dir.substring(1); 
            }
            let d = originDir;
            let arr = dir.split('/');
            for (let i = 0;i < arr.length;i++) {
                if (!arr[i]){
                    arr.splice(i,1);
                    i=i-1;
                }
            }
            for (let i = 0;i < arr.length;i++){
                d += `/${arr[i]}`;
                if (!await existsDir(d)){
                    await makeDir(d);
                    let reg = /\\/ig;
                    let filepath = d.replace(reg,'/').split('public')[1];
                    let dir = filepath.split(arr[i])[0];
                    let idx = 0;
                    await fileModel.find({
                        username:username,
                        dir:dir,
                        isFile:0,
                        part:part
                    }).count().then(num=>{
                        idx = num + 1;
                    }).catch(error=>{
                        console.log(error);
                    })
                    let m = new fileModel({
                        username:username,
                        filename:arr[i],
                        filepath:filepath,
                        type:'dir',
                        size:0,
                        dir:dir,
                        isFile:0,
                        idx:idx,
                        part:part,
                        key:`${new Date().getTime()+Math.random()}`
                    });
                    await m.save();
                }
            }
            
            let fileInfo = files[nameSpace];
            console.log(`${d}/${fileInfo.name}`)
            console.log(await existsDir( `${d}/${fileInfo.name}`))
            if (await existsDir( `${d}/${fileInfo.name}`)) {
                ctx.body = cf.dealErrorReq('文件已存在！');
                return;
            }
            //上传文件
            let fileStat = (await uploadController(files,d))[0];
            let reg = /\\/ig;
            if (fileStat){
                let filepath = d.replace(reg,'/').split('public')[1]+'/'+fileStat.filename;
                let dir = d.replace(reg,'/').split('public')[1]+'/';
                let arr = fileStat.filename.split('.');
                let filetype = arr[arr.length-1];
                let idx = 0;
                await fileModel.find({
                    username:username,
                    part:part,
                    dir:dir,
                    isFile:1
                }).count().then(num=>{
                    idx = 1+num;
                }).catch(error=>{
                    console.log(error);
                })
                let m = new fileModel({
                    username:username,
                    filename:fileStat.filename,
                    filepath:filepath,
                    type:filetype,
                    size:fileStat.filesize/1024,
                    part:part,
                    dir:dir,
                    isFile:1,
                    idx:idx,
                    key:`${new Date().getTime()+Math.random()}`
                });
                m.save().then((doc)=>{
                    console.log(doc)
                    ctx.body = cf.dealSuccessReq(doc);
                }).catch((error)=>{
                    ctx.body = cf.dealErrorReq(error);
                });
                ctx.body = cf.dealSuccessReq(m);
            }else{
                ctx.body = cf.dealErrorReq('未知错误');
            }
        } else if (ctx.request.method.toLowerCase() === 'options') {
            ctx.body = cf.dealErrorReq('received upload:\n\n');
        }
    }

    async download(ctx,next) {
        if (! await checkLogin(ctx)) {
            ctx.throw(401, 'invalid token');
        }
        const ch = checkParams(['_id'],ctx.request.query);
        if (!ch.status) {
            ctx.body = cf.dealMissArgsReq(ch.msg);
            return;
        }
        let params = ctx.request.query;
        let {_id} = params;
        await fileModel.findById(_id).then(async (doc)=>{
            if (doc) {
                if (doc.isFile) {
                    const p = path.join(__dirname, `../../public${doc.filepath}`);
                    ctx.attachment(decodeURI(p));
                    await sendfile(ctx, p);
                }else{
                    const p = path.join(__dirname, `../../public${doc.filepath}`);
                    let tmp = `${doc.filename.split('.')[0]}${parseInt(Math.random()*9999999)}.zip`;
                    
                    const zipStream = fs.createWriteStream(tmp);
                    const zip = archiver('zip');
                    zip.on('error', function(err){
                        throw err;
                    });
                    await zip.pipe(zipStream);
                    // 添加整个文件夹到压缩包
                    await zip.directory(p);
                    await zip.finalize();
                    ctx.attachment(decodeURI(tmp));
                    await sendfile(ctx, tmp).then(async ()=>{
                        await deleteFile(tmp);
                    }).catch(async ()=>{
                        await deleteFile(tmp);
                    })
                }
            }
        }).catch(error=>{
            ctx.body = cf.dealErrorReq(error);
        })
    }

    async findList(ctx,next){
        if (! await checkLogin(ctx)) {
            ctx.throw(401, 'invalid token');
        }
        const ch = checkParams(['nameSpace'],ctx.request.body);
        if (!ch.status) {
            ctx.body = cf.dealMissArgsReq(ch.msg);
            return;
        }
        console.log(ctx.request.body)
        let params = ctx.request.body;
        let {part,nameSpace} = params;
        let username = await getUsername(ctx);
        let find = {username};
        if (params.part !== undefined) {
            find.part = params.part;
        }
        if (params.keyword !== undefined) {
            find.filepath = {$regex:params.keyword,$options:'ig'}
        }
        if (params.type !== undefined) {
            find.type = params.type;
        }
        if (params.dir !== undefined) {
            find.dir = `/files/${username}/${nameSpace}/${params.dir}`
            if (!find.dir.endsWith('/')) find.dir += '/';
        }
        if (params.timeStart !== undefined && params.timeEnd !== undefined) {
            find.created_at = {
                $gte:new Date(params.timeStart),
                $lte:new Date(params.timeEnd)
            }
        }
        if (params.minSize !== undefined && params.maxSize !== undefined) {
            find.size = {
                $gte:parseFloat(params.minSize),
                $lte:parseFloat(params.maxSize)
            }
        }
        if (params.keywords !== undefined) {
            find['$text'] = {$search:params.keywords};
        }
        let page = parseInt(params.page) || 1;
        let pageCount = parseInt(params.pageCount) || 50;
        let sort = {idx:-1,isFile:-1};
        if (params.sort) {
            sort = {isFile:-1};
            sort[params.sort] = -1;
        }
        console.log('find===============',find)
        await fileModel.find(find)
        .sort(sort)
        .skip((page-1)*pageCount)
        .limit(pageCount)
        .then(async (docs)=>{
            ctx.body = cf.dealSuccessReq(docs);
        })
        .catch((error)=>{
            ctx.body = cf.dealErrorReq(error);
        });
    }

    async findById(ctx,next){
        const ch = checkParams(['_id'],ctx.request.body);
        if (!ch.status) {
            ctx.body = cf.dealMissArgsReq(ch.msg);
            return;
        }
        let {_id} = ctx.request.body;
        await fileModel.findById(_id).then(async (doc)=>{
            ctx.body = cf.dealSuccessReq(doc);
        }).catch(error => {
            ctx.body = cf.dealErrorReq(error);
        });
    }

    async changeIndex (ctx,next) {
        if (! await checkLogin(ctx)) {
            ctx.throw(401, 'invalid token');
        }
        const ch = checkParams(['origin','target','dragIndex','hoverIndex'],ctx.request.body);
        if (!ch.status) {
            ctx.body = cf.dealMissArgsReq(ch.msg);
            return;
        }
        let {origin,target,dragIndex,hoverIndex} = ctx.request.body;
        await fileModel.updateOne({
            _id:origin
        },{idx:parseInt(dragIndex)}).catch(error=>{
            ctx.body = cf.dealErrorReq(0);
        });
        await fileModel.updateOne({
            _id:target
        },{idx:parseInt(hoverIndex)}).catch(error=>{
            ctx.body = cf.dealErrorReq(0);
        });
        ctx.body = cf.dealSuccessReq(1);
    }

    async deleteList(ctx,next){
        console.log('ctx');
    }

    async deleteById(ctx,next){
        if (! await checkLogin(ctx)) {
            ctx.throw(401, 'invalid token');
        }
        const ch = checkParams(['_id'],ctx.request.body);
        if (!ch.status) {
            ctx.body = cf.dealMissArgsReq(ch.msg);
            return;
        }
        const {_id} = ctx.request.body;
        await fileModel.findByIdAndRemove(_id).then(async (doc)=>{
            console.log(path);
            await deleteFile(doc.filepath);
            ctx.body = cf.dealSuccessReq(1);
        }).catch(error=>{
            ctx.body = cf.dealErrorReq(0);
        });
    }

    async updateList(ctx,next){
        console.log('ctx');
    }

    async updateById(ctx,next){
        console.log('ctx');
    }

    async newFolder(ctx,next){
        if (! await checkLogin(ctx)) {
            ctx.throw(401, 'invalid token');
        }
        const ch = checkParams(['part','nameSpace','dir','dirName'],ctx.request.body);
        if (!ch.status) {
            ctx.body = cf.dealMissArgsReq(ch.msg);
            return;
        }
        const {part,nameSpace,dir,dirName} = ctx.request.body;
        let username = await getUsername(ctx);
        if (!await existsDir(path.join(__dirname, `../../public/files`))) {
            await makeDir(path.join(__dirname, `../../public/files`));
        }
        if (!await existsDir(path.join(__dirname, `../../public/files/${username}`))){
            await makeDir(path.join(__dirname, `../../public/files/${username}`));
        }
        if (!nameSpace) {
            ctx.body = cf.dealErrorReq('未定义文件命名空间');
            return;
        }
        let originDir = path.join(__dirname, `../../public/files/${username}/${nameSpace}`);
        
        if (!await existsDir(originDir)){
            await makeDir(originDir);
            let idx = 0;
            let reg = /\\/ig;
            await fileModel.find({
                username:username,
                dir:originDir.replace(reg,'/').split('public')[1].split(nameSpace)[0],
                isFile:0,
                part:''
            }).count().then(num=>{
                idx = num + 1;
            }).catch(error=>{
                console.log(error);
            })
            let m = new fileModel({
                username:username,
                filename:nameSpace,
                filepath:`/${nameSpace}`,
                type:'dir',
                size:0,
                dir:originDir.replace(reg,'/').split('public')[1].split(nameSpace)[0],
                isFile:0,
                idx:idx,
                key:`${new Date().getTime()+Math.random()}`
            });
            await m.save();
        }
        if (dir && dir.startsWith('/')){
            dir = dir.substring(1); 
        }
        if (dir && dir.endsWith('/')){
            dir = dir.substring(-2); 
        }
        let d = originDir;
        let arr = dir.split('/');
        arr.push(dirName);
        for (let i = 0;i < arr.length;i++) {
            if (!arr[i]){
                arr.splice(i,1);
                i=i-1;
            }
        }
        for (let i = 0;i < arr.length;i++){
            d += `/${arr[i]}`;
            if (!await existsDir(d)){
                await makeDir(d);
                let reg = /\\/ig;
                let filepath = d.replace(reg,'/').split('public')[1];
                let dir = filepath.split(arr[i])[0];
                let idx = 0;
                await fileModel.find({
                    username:username,
                    dir:dir,
                    isFile:0,
                    part:part
                }).count().then(num=>{
                    idx = num + 1;
                }).catch(error=>{
                    console.log(error);
                })
                let m = new fileModel({
                    username:username,
                    filename:arr[i],
                    filepath:filepath,
                    type:'dir',
                    size:0,
                    dir:dir,
                    isFile:0,
                    idx:idx,
                    part:part,
                    key:`${new Date().getTime()+Math.random()}`
                });
                await m.save();
            }
        }
        ctx.body = cf.dealSuccessReq(1);
    }

}

module.exports = new Controller();

